#include "Shader.h"
#include <iostream>
#include <fstream>
#include <iomanip>

Shader::Shader(const char *vertexPath, const char *fragmentPath)
{
	unsigned int vertexShader = compile(vertexPath, GL_VERTEX_SHADER);
	unsigned int fragmentShader = compile(fragmentPath, GL_FRAGMENT_SHADER);
	m_id = link(vertexShader, fragmentShader);
}

Shader::~Shader()
{
	glDeleteProgram(m_id);
}

void Shader::bind() const
{
	glUseProgram(m_id);
}

void Shader::unbind() const
{
	glUseProgram(0);
}

unsigned int Shader::compile(const char *path, unsigned int type)
{
	std::ifstream infile;
	std::string source;
	try
	{
		infile.open(path);
		std::stringstream sstream;
		sstream << infile.rdbuf();
		infile.close();
		source = sstream.str();
	}
	catch (...)
	{
		std::cout << "Shader read fail\nfilepath " << path << std::endl;
		assert(0);
	}
	const char *src = source.c_str();
	unsigned int id = glCreateShader(type);
	glShaderSource(id, 1, &src, nullptr);
	glCompileShader(id);
	int ok;
	char infoLogBuf[512];
	glGetShaderiv(id, GL_COMPILE_STATUS, &ok);
	if (!ok)
	{
		glGetShaderInfoLog(id, 512, nullptr, infoLogBuf);
		glDeleteShader(id);
		std::cout << "shader compile fail \nfilepath" << path << "\ninfo" << infoLogBuf << std::endl;
		assert(0);
	}
	return id;
}

unsigned int Shader::link(unsigned int vertexShader, unsigned int fragmentShader)
{
	unsigned int id = glCreateProgram();
	glAttachShader(id, vertexShader);
	glAttachShader(id, fragmentShader);
	glLinkProgram(id);
	char infoLogBuf[512];
	int ok;
	glGetProgramiv(id, GL_LINK_STATUS, &ok);
	if (!ok)
	{
		glGetProgramInfoLog(id, 512, nullptr, infoLogBuf);
		glDeleteProgram(id);
		glGetShaderInfoLog(id, 512, nullptr, infoLogBuf);
		glDeleteShader(id);
		std::cout << "shader link fail\n"
				  << "info" << infoLogBuf << std::endl;
		assert(0);
	}
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);
	return id;
}
